package com.app.util.db.where;

import com.app.util.string.StringUtil;

public class Expression {

	private boolean not = false;

	protected Object left;

	protected String link;

	protected Object right;

	private static final Object NULL = new Object();

	public static final Expression TRUE = new Expression("1").eq(1);

	public static final Expression FALSE = new Expression("1").eq(0);

	public Expression(String left) {
		super();
		this.left = left; 
	}

	public Expression(Expression left) {
		super();
		this.left = left;
	}

	public Expression like(String str) {
		this.right = str;
		this.link = "like";
		return this;
	}

	public Expression isNull() {
		this.right = NULL;
		this.link = "IS";
		return this;
	}

	public Expression isNotNull() {
		this.right = NULL;
		this.link = "IS NOT";
		return this;
	}

	public Expression in(Object[] right) {
		this.right = right;
		this.link = "IN";
		return this;
	}

	public Expression eq(Object right) {
		this.right = right;
		this.link = "=";
		return this;
	}

	public Expression neq(Object right) {
		this.right = right;
		this.link = "!=";
		return this;
	}

	public Expression lt(Object right) {
		this.right = right;
		this.link = "<";
		return this;
	}

	public Expression gt(Object right) {
		this.right = right;
		this.link = ">";
		return this;
	}

	public Expression lteq(Object right) {
		this.right = right;
		this.link = "<=";
		return this;
	}

	public Expression gteq(Object right) {
		this.right = right;
		this.link = ">=";
		return this;
	}

	public static Expression and(Expression left, Expression right) {
		Expression e = new Expression(left);
		e.right = right;
		e.link = "AND";
		return e;
	}

	public static Expression or(Expression left, Expression right) {
		Expression e = new Expression(left);
		e.right = right;
		e.link = "OR";
		return e;
	}

	public static Expression not(Expression e) {
		e.not = true;
		return e;
	}

	public String toString() {
		String rightString;
		if (right instanceof Expression) {
			rightString = StringUtil.toString(right);
		} else if (right == NULL) {
			rightString = "NULL";
		} else if (right instanceof Object[]) {
			StringBuffer rightSB = new StringBuffer("(");
			for (int i = 0; i < ((Object[]) right).length; i++) {
				if (i > 0) {
					rightSB.append(',');
				}
				rightSB.append('?');
			}
			rightSB.append(')');
			rightString = rightSB.toString();
		} else {
			rightString = "?";
		}
		StringBuffer sb = new StringBuffer();
		sb.append(not ? " NOT (" : "");

		if (left instanceof Expression) {
			sb.append(left);
		} else if (left.equals("1")) {
			sb.append(left);
		} else {
			sb.append("`").append(left).append("`");
		}

		sb.append(" ").append(link).append(" ");
		sb.append(rightString);
		sb.append(not ? ")" : "");
		return sb.toString();
	}

	public Object[] getParams() {
		Object[] params = new Object[] {};
		if (left instanceof Expression) {
			Object[] leftParams = ((Expression) left).getParams();
			params = new Object[params.length + leftParams.length];
			System.arraycopy(params, 0, params, leftParams.length, params.length - leftParams.length);
			System.arraycopy(leftParams, 0, params, 0, leftParams.length);
		}
		if (NULL == right) {
			return params;
		}
		if (right instanceof Expression) {
			Object[] rightParams = ((Expression) right).getParams();
			Object[] tmpParams = new Object[params.length + rightParams.length];
			System.arraycopy(params, 0, tmpParams, 0, params.length);
			System.arraycopy(rightParams, 0, tmpParams, tmpParams.length - rightParams.length, rightParams.length);
			params = tmpParams;
		} else if (right instanceof Object[]) {
			Object[] tmpParams = new Object[params.length + ((Object[]) right).length];
			System.arraycopy(params, 0, tmpParams, 0, params.length);
			System.arraycopy((Object[]) right, 0, tmpParams, params.length, ((Object[]) right).length);
			params = tmpParams;
		} else {
			Object[] tmpParams = new Object[params.length + 1];
			System.arraycopy(params, 0, tmpParams, 0, params.length);
			params = tmpParams;
			params[params.length - 1] = right;
		}
		return params;
	}

	public String toWhereString() {
		return "WHERE " + toString();
	}

	public static void main(String[] args) {
		Expression e = new Expression("name").eq("viqje");

		e = Expression.and(e, new Expression("age").isNull());
		e = Expression.not(e);

		System.out.println(e);
		System.out.println(StringUtil.linkString(e.getParams(), ", "));

		e = Expression.and(e, new Expression("name").isNotNull());
		e = Expression.and(e, new Expression("sex").isNotNull());
		e = Expression.and(e, new Expression("address").isNotNull());
		e = Expression.and(e, new Expression("phone").isNotNull());
		e = Expression.not(e);

		System.out.println(e);
		System.out.println(StringUtil.linkString(e.getParams(), ", "));

		e = Expression.not(e);

		System.out.println(e);
		System.out.println(StringUtil.linkString(e.getParams(), ", "));

		System.out.println(Expression.TRUE);

		Expression e2 = new Expression("name").in(new Object[] { 1, 2, "yao" });
		e2 = Expression.and(e2, new Expression("name").eq("viqje"));
		System.out.println(e2.toWhereString());
		System.out.println(StringUtil.linkString(e2.getParams(), ","));
	}
}
